﻿using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DistributedIDGenerator;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using Mrhd.Core.Entities;
using Mrhd.Core.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Mrhd.Application
{
    public class ProductService : IProductService, IScoped
    {
        private readonly IRepository<ProductEntity> _repository;

        public ProductService(IRepository<ProductEntity> repository)
        {
            _repository = repository;
        }


        public async Task<List<ProductTypeEntity>> GetProductTypesAsync()
        {
            var repo = _repository.Change<ProductTypeEntity>();
            return await repo.Entities.AsNoTracking().ToListAsync();
        }

        public async Task<List<ProductEntity>> GetProductsAsync(int typeId, int status, string key, PagingQuery paging)
        {
            var query = _repository.Where(a => !a.IsDeleted);
            if (typeId > 0)
            {
                query = query.Where(a => a.ProductTypeId == typeId);
            }
            if (status != 99)       // 默认99标识不筛选商品状态
            {
                query = query.Where(a => a.Status == (ProductStatus)status);
            }
            if (!string.IsNullOrEmpty(key))
            {
                query = query.Where(a => a.Name.Contains(key) || a.Pinyin.Contains(key) || a.FirstLetter.Contains(key));
            }
            paging.RecordCount = await query.CountAsync();
            var pageList = await query
                .AsNoTracking()
                .OrderBy(a => a.Sort)
                .Include(a => a.Images)
                .ToPagedListAsync(paging.PageIndex, paging.PageSize);
            var list = pageList.Items.ToList();
            return list;
        }

        public async Task SaveProductTypeAsync(IEnumerable<ProductTypeEntity> types)
        {
            var repo = _repository.Change<ProductTypeEntity>();
            var entities = await repo.Entities.ToListAsync();
            // 找到各种状态的商品类型
            var adds = types.Where(a => a.Flag == EntitySign.Add);
            var updates = types.Where(a => a.Flag == EntitySign.Update);
            var deletes = types.Where(a => a.Flag == EntitySign.Delete);
            // 1. 新增
            adds.ForEach(a => a.CreatedTime = DateTimeOffset.Now);
            await repo.InsertAsync(adds);
            // 2. 修改
            updates.ForEach(a =>
            {
                var entity = entities.FirstOrDefault(b => b.Id == a.Id);
                entity.Name = a.Name;
                entity.Sort = a.Sort;
            });
            // 3. 删除
            await deletes.ForEachAsync(async a =>
            {
                var entity = entities.FirstOrDefault(b => b.Id == a.Id);
                await repo.DeleteAsync(entity);
            });
            // 4. 保存
            await repo.SaveNowAsync();
        }

        public async Task<int> GetProductMaxSortAsync(int typeId)
        {
            var sort = await _repository.Where(a => a.ProductTypeId == typeId).MaxAsync(a => a.Sort);
            return sort;
        }

        public async Task<ProductEntity> CreateProductAsync(ProductEntity product)
        {
            var now = DateTimeOffset.Now;
            product.CreatedTime = now;
            if (string.IsNullOrEmpty(product.Code))
            {
                product.Code = await GenerateProductCodeAsync();
            }
            product.Pinyin = product.Name.ToPinyin();
            product.FirstLetter = product.Name.ToFirstLatter();
            product.Status = ProductStatus.Sale;
            product.UpTime = now;
            if (product.Images != null)
            {
                product.Logo = product.Images.FirstOrDefault()?.Name;
            }
            product.Images?.ForEach(a => a.CreatedTime = now);
            await _repository.InsertAsync(product);
            await _repository.SaveNowAsync();
            return product;
        }

        public async Task<ProductEntity> UpdateProductAsync(ProductEntity product)
        {
            var now = DateTimeOffset.Now;
            var entity = await _repository.Include(a => a.Images).FirstOrDefaultAsync(a => a.Id == product.Id);
            entity.Name = product.Name;
            entity.Pinyin = product.Name.ToPinyin();
            entity.FirstLetter = product.Name.ToFirstLatter();
            entity.Description = product.Description;
            entity.UnitName = product.UnitName;
            entity.Price = product.Price;
            entity.Stock = product.Stock;
            entity.UPC = product.UPC;
            entity.SKU = product.SKU;
            entity.UpdatedTime = now;
            entity.Attributes = product.Attributes;
            entity.IsDiscount = product.IsDiscount;
            entity.Sort = product.Sort;
            entity.ProductTypeId = product.ProductTypeId;

            // 保存图片
            // 1. 删除图片
            var repoImage = _repository.Change<ProductImageEntity>();
            entity.Images?.ForEach(image =>
            {
                var item = product.Images?.FirstOrDefault(a => a.Id == image.Id);
                if (item == null)
                {
                    repoImage.DeleteAsync(image);
                }
            });
            // 2. 新增图片
            var notSaveImages = product.Images?.Where(a => a.Id == 0);
            if (notSaveImages != null)
            {
                notSaveImages.ForEach(a =>
                {
                    a.ProductId = product.Id;
                    a.CreatedTime = now;
                });
                await repoImage.InsertAsync(notSaveImages);
            }
            // 默认将第一章图片设置为商品LOGO
            entity.Logo = product.Images?.FirstOrDefault()?.Name;

            // 保存修改
            await _repository.SaveNowAsync();
            // 
            entity.Images = product.Images;

            return entity;
        }

        public async Task<bool> ChangeStatusAsync(int id, ProductStatus status)
        {
            var now = DateTimeOffset.Now;
            var entity = await _repository.FindAsync(id);
            entity.Status = status;
            entity.UpdatedTime = now;
            if (status == ProductStatus.Sale)
            {
                entity.UpTime = now;
            }
            else
            {
                entity.DownTime = now;
            }
            await _repository.SaveNowAsync();
            return true;
        }

        public async Task<bool> ChangeStatusAsync(IEnumerable<int> ids, ProductStatus status)
        {
            var now = DateTimeOffset.Now;
            var entities = await _repository.Where(a => ids.Contains(a.Id)).ToListAsync();
            entities.ForEach(a => 
            {
                a.Status = status;
                a.UpdatedTime = now;
                if (status == ProductStatus.Sale)
                {
                    a.UpTime = now;
                }
                else
                {
                    a.DownTime = now;
                }
            });
            await _repository.SaveNowAsync();
            return true;
        }

        public async Task<bool> DeleteAsync(int id)
        {
            var entity = new ProductEntity { Id = id, IsDeleted = true, UpdatedTime = DateTimeOffset.Now };
            await _repository.UpdateExcludeAsync(entity, new[] { nameof(entity.IsDeleted), nameof(entity.UpdatedTime) });
            await _repository.SaveNowAsync();
            return true;
        }

        public async Task<bool> DeleteAsync(IEnumerable<int> ids)
        {
            var now = DateTimeOffset.Now;
            var entities = await _repository.Where(a => ids.Contains(a.Id)).ToListAsync();
            entities.ForEach(a =>
            {
                a.IsDeleted = true;
                a.UpdatedTime = now;
            });
            await _repository.SaveNowAsync();
            return true;
        }


        /// <summary>
        /// 生成商品编码
        /// </summary>
        /// <returns></returns>
        private async Task<string> GenerateProductCodeAsync()
        {
            var code = string.Empty;
            var now = DateTime.Now;
            while (true)
            {
                code = $"80{now.Year}0{"".RandomNumber(4)}{now:MMdd}0{"".RandomNumber(4)}";
                var exist = await _repository.AnyAsync(a => a.Code == code);
                if (!exist) break;
            }
            return code;
        }

    }
}
